import java.awt.Point;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Random;


public class DBLP 
{
	// global variables
	private Author[] authorsMap;
	private double[][] coordinates;
	private DBLPDatabase db;
	
	private double alpha = 1;
	private double beta = 1;
	private double gamma = 0.001;
	private double wij = 1;
	int x_min =0;
	int x_max =10000;
	int y_min =0; 
	int y_max =10000;
	ViewGraph v;
	//-------------------------------------------------
	public static void main(String args[])
	{
		new DBLP();
	}
	public DBLP()
	{
		try
		{
			db = new DBLPDatabase();
			int numberOfAuthors = db.getNumberOfAuthors();
			authorsMap = new Author[numberOfAuthors];
			coordinates = new double[numberOfAuthors][2];
			initializeCoordinates();
			//printCoordinates();
			initializeAuthorsMap();
			loadMap("test.txt");
			
			//CalculateStress();
			gradiantDescent();
			v = new ViewGraph(coordinates);
			
		}
		catch(Exception ex)
		{
			System.out.println("Error 001:"+ ex.getMessage());
		}
	}
	//=========== load map ====================
	public void loadMap(String fileName)
	{
		int count = 0;
		System.out.println(">Loading the map structure ... ");
		try
		{
			File file = new File(fileName);
			FileReader fileReader = new FileReader(file);
			BufferedReader buffer = new BufferedReader(fileReader);
			//boolean link = true;
			while(true)
			{
				String line = buffer.readLine();
				if(line == null)break;
				String[] splitNodes = line.split("-");
				int aID = Integer.parseInt(splitNodes[0].split(",")[0]);
				Author author = new Author(aID);
				//System.out.println(splitNodes[0]);
				for(int i=1;i<splitNodes.length;i++)
				{
					int coID = Integer.parseInt(splitNodes[i].split(",")[0]);
					double weight = Double.parseDouble(splitNodes[i].split(",")[1]);
					author.addCoAuthor(coID,(int)weight);
				}
				authorsMap[aID-1] = author;
				count++;
			}
			//System.out.println(count);
			System.out.println(">Loading the map structure has been completed with ["+ count + "] authors");
		
		}
		catch(Exception ex)
		{
			System.out.println("Error 001:"+ex.getMessage());
		}
		 
	}
	//=============================================
	public void printCoauthorsList(int authorID)
	{
		System.out.println(authorsMap[authorID-1].getStringOfCo_Authors());
	}
	//==============================================
	public void initializeAuthorsMap()
	{
		for(int i=0;i<authorsMap.length;i++)
		{
			Author author = new Author(i+1);
			authorsMap[i] = author;
		}
	}
	//==============================================
	private void initializeCoordinates()
	{
		System.out.println(">initializing authors coordinates ... randomlly");
		
		Random r = new Random();
		for(int i=0;i<coordinates.length;i++)
		{
			
			double x = r.nextDouble()*(x_max-x_min) + x_min;
			double y = r.nextDouble()*(y_max-y_min) + y_min;
			coordinates[i][0] = x;
			coordinates[i][1] = y;
			//System.out.println("Point [" + i+ "[ has coordinate of (" + x + "," + y + ")");
	
		}
		System.out.println(">["+ coordinates.length + "] coordinates have been completed");
	}
	//================================================
	public double getIdealDistance(int aID1,int aID2)
	{
		double f = 0.0;
		int weight = authorsMap[aID1-1].getWeight(aID2);
		if(weight>0)
		{
			f = alpha * Math.pow(weight, -1*beta);
		}
		return f;
	}
	//===================================================
	public double getDistance(int aid1,int aid2)
	{
		double d = 0.0;
		// calc dij(x) = sqrt((xi2 - xj1)^2 + (xi2 - xj2)^2)
		double c1 = (coordinates[aid2-1][0] - coordinates[aid1-1][0]);
		double c2 = (coordinates[aid2-1][1] - coordinates[aid1-1][1]);
		double sum = Math.pow(c1,2) + Math.pow(c2,2);
		d = Math.sqrt(sum);
		return d;
	}
	//==================================================
	public double CalculateStress()
	{
		double diff_sum =0;
		double dis_sum = 0;
		double stress = 0;
		for(int i=0;i<authorsMap.length;i++)
		{
			//System.out.println(authorsMap[i].authorID);
			int aid1 = authorsMap[i].authorID;
			Integer[] listOfCoauthorsID = authorsMap[i].getCoauthorsID();
			for(int j=0;j<listOfCoauthorsID.length;j++)
			{
				int aid2 = listOfCoauthorsID[j];
				diff_sum = diff_sum + Math.pow((getIdealDistance(aid1,aid2) - getDistance (aid1, aid2)),2);
				dis_sum = dis_sum + Math.pow(getDistance (aid1, aid2),2);
				
				//System.out.println(aid1 + ":" + points[aid1-1].x + "," +aid2 +":"+ points[aid2-1].x);
			}
			//System.out.println(aid1 + ":" + points[aid1-1].x );
		}
		stress = (diff_sum/2);
		System.out.println("Stress = " + stress);
		return stress;
	}
	//==================================================
	public double calculatePartialDiffStress()
	{
		double diff_sum_2 =0;
		double stress = 0;
		double sum_pStress = 0;
		for(int i=0;i<authorsMap.length;i++)
		{
			double pXi1 = 0;
			double pXi2 = 0;
			//System.out.println(authorsMap[i].authorID);
			int aid1 = authorsMap[i].authorID;
			Integer[] listOfCoauthorsID = authorsMap[i].getCoauthorsID();
			for(int j=0;j<listOfCoauthorsID.length;j++)
			{
				
				int aid2 = listOfCoauthorsID[j];
				if(aid1!=aid2)
				{
					// sum [wij(fij - dij)^2]
					diff_sum_2 = diff_sum_2 + wij * Math.pow((getIdealDistance(aid1,aid2) - getDistance (aid1, aid2)),2);
					// sum[( fij - dij(x)) . dij(x)^-1 . (Xi1 - Xj1)
					double t1 = getIdealDistance(aid1,aid2) - getDistance (aid1, aid2);
					double t2 = 1/getDistance (aid1, aid2);
					double t31 = coordinates[aid1-1][0] - coordinates[aid2-1][0];
					double t32 = coordinates[aid1-1][1] - coordinates[aid2-1][1];
				
				
					pXi1 = pXi1 + t1*t2*t31;
					pXi2 = pXi2 + t1*t2*t32;
					
					//sum_pStress = sum_pStress + getDistance(aid1,aid2);
				}
				
			}
			//----test ----------------------------------------
			pXi1 = -2*pXi1;
			pXi2 = -2*pXi2;
			coordinates[aid1-1][0] = coordinates[aid1-1][0] - gamma * pXi1;
			coordinates[aid1-1][1] = coordinates[aid1-1][1] - gamma * pXi2;
			
			//-----------------------------------------------
		}
		stress = diff_sum_2;
		System.out.println("Stress = " + stress);
		
		return stress;
	}
	//==================================================
	public void gradiantDescent()
	{
		for(int k=0;k<150;k++)
		{
			System.out.println("Iteration # " + k);
			double pdStress = calculatePartialDiffStress();
			//v.updatePaint();
		}
	}
	//=====================================================
	public Point getRandomPoint(double radius,Point center)
	{
		int x = 0;
		int y = 0;
		Random r = new Random();
		
		x = (int) (radius * Math.sin(Math.toRadians(r.nextInt(90))));
		y = (int) (radius * Math.cos(Math.toRadians(r.nextInt(90))));
		//System.out.println(radius + ", " + (center.x) + ", " + (center.y));
		//System.out.println( (x) + ", " + (y));
		Point p = new Point(Math.abs(x - center.x),Math.abs(y - center.y));
		//if(radius>100000)
			System.out.println(radius + ", " + Math.abs(x - center.x) + ", " + Math.abs(y - center.y));
		return p;
	}
	//======================================================
	public Point getNewPoint(double dist, Point p1,Point p2) 
	{
		double cos = (p2.x-p1.x)/dist;
		double sin = (p2.y-p1.y)/dist;
		
		double new_x = dist * sin + p1.x;
		double new_y = dist * cos + p1.y;
		
		//System.out.println(dist +", "  + new_x + ", "  + new_y);
		return new Point((int) new_x%1000,(int) new_y%1000);
	}
	//=======================================================
	private void printCoordinates()
	{
		for(int i=0;i<coordinates.length;i++)
		{
			System.out.println("Point [" + i+ "]: (" + coordinates[i][0] + "," + coordinates[i][1] + ")");
		}
	}
	
}
